home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / Mesa-3.0 / SRC-GLUT / GLUT_WIN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-07-23  |  27.9 KB  |  1,001 lines

  1.  
  2. /* Copyright (c) Mark J. Kilgard, 1994, 1997.  */
  3.  
  4. /* This program is freely distributable without licensing fees
  5.    and is provided without guarantee or warrantee expressed or
  6.    implied. This program is -not- in the public domain. */
  7.  
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <assert.h>
  12. #if !defined(_WIN32)
  13. #include <X11/Xlib.h>
  14. #include <X11/Xatom.h>
  15. #endif
  16.  
  17. #include "glutint.h"
  18.  
  19. GLUTwindow *__glutCurrentWindow = NULL;
  20. GLUTwindow **__glutWindowList = NULL;
  21. int __glutWindowListSize = 0;
  22. #if !defined(_WIN32)
  23. GLUTstale *__glutStaleWindowList = NULL;
  24. #endif
  25. GLUTwindow *__glutMenuWindow = NULL;
  26.  
  27. void (*__glutFreeOverlayFunc) (GLUToverlay *);
  28. XVisualInfo *(*__glutDetermineVisualFromString) (char *string, Bool * treatAsSingle,
  29.   Criterion * requiredCriteria, int nRequired, int requiredMask, void** fbc) = NULL;
  30.  
  31. static Criterion requiredWindowCriteria[] =
  32. {
  33.   {LEVEL, EQ, 0},
  34.   {TRANSPARENT, EQ, 0}
  35. };
  36. static int numRequiredWindowCriteria = sizeof(requiredWindowCriteria) / sizeof(Criterion);
  37. static int requiredWindowCriteriaMask = (1 << LEVEL) | (1 << TRANSPARENT);
  38.  
  39. static void
  40. cleanWindowWorkList(GLUTwindow * window)
  41. {
  42.   GLUTwindow **pEntry = &__glutWindowWorkList;
  43.   GLUTwindow *entry = __glutWindowWorkList;
  44.  
  45.   /* Tranverse singly-linked window work list look for the
  46.      window. */
  47.   while (entry) {
  48.     if (entry == window) {
  49.       /* Found it; delete it. */
  50.       *pEntry = entry->prevWorkWin;
  51.       return;
  52.     } else {
  53.       pEntry = &entry->prevWorkWin;
  54.       entry = *pEntry;
  55.     }
  56.   }
  57. }
  58.  
  59. #if !defined(_WIN32)
  60.  
  61. static void
  62. cleanStaleWindowList(GLUTwindow * window)
  63. {
  64.   GLUTstale **pEntry = &__glutStaleWindowList;
  65.   GLUTstale *entry = __glutStaleWindowList;
  66.  
  67.   /* Tranverse singly-linked stale window list look for the
  68.      window ID. */
  69.   while (entry) {
  70.     if (entry->window == window) {
  71.       /* Found it; delete it. */
  72.       *pEntry = entry->next;
  73.       free(entry);
  74.       return;
  75.     } else {
  76.       pEntry = &entry->next;
  77.       entry = *pEntry;
  78.     }
  79.   }
  80. }
  81.  
  82. #endif
  83.  
  84. static GLUTwindow *__glutWindowCache = NULL;
  85.  
  86. GLUTwindow *
  87. __glutGetWindow(Window win)
  88. {
  89.   int i;
  90.  
  91.   /* Does win belong to the last window ID looked up? */
  92.   if (__glutWindowCache && (win == __glutWindowCache->win ||
  93.       (__glutWindowCache->overlay && win ==
  94.         __glutWindowCache->overlay->win))) {
  95.     return
  96.       __glutWindowCache;
  97.   }
  98.   /* Otherwise scan the window list looking for the window ID. */
  99.   for (i = 0; i < __glutWindowListSize; i++) {
  100.     if (__glutWindowList[i]) {
  101.       if (win == __glutWindowList[i]->win) {
  102.         __glutWindowCache = __glutWindowList[i];
  103.         return __glutWindowCache;
  104.       }
  105.       if (__glutWindowList[i]->overlay) {
  106.         if (win == __glutWindowList[i]->overlay->win) {
  107.           __glutWindowCache = __glutWindowList[i];
  108.           return __glutWindowCache;
  109.         }
  110.       }
  111.     }
  112.   }
  113. #if !defined(_WIN32)
  114.   {
  115.     GLUTstale *entry;
  116.  
  117.     /* Scan through destroyed overlay window IDs for which no
  118.        DestroyNotify has yet been received. */
  119.     for (entry = __glutStaleWindowList; entry; entry = entry->next) {
  120.       if (entry->win == win)
  121.         return entry->window;
  122.     }
  123.   }
  124. #endif
  125.   return NULL;
  126. }
  127.  
  128. /* CENTRY */
  129. int APIENTRY
  130. glutGetWindow(void)
  131. {
  132.   if (__glutCurrentWindow) {
  133.     return __glutCurrentWindow->num + 1;
  134.   } else {
  135.     return 0;
  136.   }
  137. }
  138. /* ENDCENTRY */
  139.  
  140. void
  141. __glutSetWindow(GLUTwindow * window)
  142. {
  143.   /* It is tempting to try to short-circuit the call to
  144.      glXMakeCurrent if we "know" we are going to make current
  145.      to a window we are already current to.  In fact, this
  146.      assumption breaks when GLUT is expected to integrated with
  147.      other OpenGL windowing APIs that also make current to
  148.      OpenGL contexts.  Since glXMakeCurrent short-circuits the
  149.      "already bound" case, GLUT avoids the temptation to do so
  150.      too. */
  151.   __glutCurrentWindow = window;
  152.  
  153.   glXMakeCurrent(__glutDisplay, __glutCurrentWindow->renderWin,
  154.     __glutCurrentWindow->renderCtx);
  155.  
  156. #if !defined(_WIN32)
  157.   /* We should be careful to force a finish between each
  158.      iteration through the GLUT main loop if indirect OpenGL
  159.      contexts are in use; indirect contexts tend to have  much
  160.      longer latency because lots of OpenGL extension requests
  161.      can queue up in the X protocol stream.  We accomplish this
  162.      by posting GLUT_FINISH_WORK to be done. */
  163.   if (!__glutCurrentWindow->isDirect)
  164.     __glutPutOnWorkList(__glutCurrentWindow, GLUT_FINISH_WORK);
  165. #endif
  166.  
  167.   /* If debugging is enabled, we'll want to check this window
  168.      for any OpenGL errors every iteration through the GLUT
  169.      main loop.  To accomplish this, we post the
  170.      GLUT_DEBUG_WORK to be done on this window. */
  171.   if (__glutDebug) {
  172.     __glutPutOnWorkList(__glutCurrentWindow, GLUT_DEBUG_WORK);
  173.   }
  174. }
  175.  
  176. /* CENTRY */
  177. void APIENTRY
  178. glutSetWindow(int win)
  179. {
  180.   GLUTwindow *window;
  181.  
  182.   if (win < 1 || win > __glutWindowListSize) {
  183.     __glutWarning("glutSetWindow attempted on bogus window.");
  184.     return;
  185.   }
  186.   window = __glutWindowList[win - 1];
  187.   if (!window) {
  188.     __glutWarning("glutSetWindow attempted on bogus window.");
  189.     return;
  190.   }
  191.   __glutSetWindow(window);
  192. }
  193. /* ENDCENTRY */
  194.  
  195. static int
  196. getUnusedWindowSlot(void)
  197. {
  198.   int i;
  199.  
  200.   /* Look for allocated, unused slot. */
  201.   for (i = 0; i < __glutWindowListSize; i++) {
  202.     if (!__glutWindowList[i]) {
  203.       return i;
  204.     }
  205.   }
  206.   /* Allocate a new slot. */
  207.   __glutWindowListSize++;
  208.   if (__glutWindowList) {
  209.     __glutWindowList = (GLUTwindow **)
  210.       realloc(__glutWindowList,
  211.       __glutWindowListSize * sizeof(GLUTwindow *));
  212.   } else {
  213.     /* XXX Some realloc's do not correctly perform a malloc
  214.        when asked to perform a realloc on a NULL pointer,
  215.        though the ANSI C library spec requires this. */
  216.     __glutWindowList = (GLUTwindow **)
  217.       malloc(sizeof(GLUTwindow *));
  218.   }
  219.   if (!__glutWindowList)
  220.     __glutFatalError("out of memory.");
  221.   __glutWindowList[__glutWindowListSize - 1] = NULL;
  222.   return __glutWindowListSize - 1;
  223. }
  224.  
  225. static XVisualInfo *
  226. getVisualInfoCI(unsigned int mode)
  227. {
  228.   static int bufSizeList[] =
  229.   {16, 12, 8, 4, 2, 1, 0};
  230.   XVisualInfo *vi;
  231.   int list[32];
  232.   int i, n = 0;
  233.  
  234.   /* Should not be looking at display mode mask if
  235.      __glutDisplayString is non-NULL. */
  236.   assert(!__glutDisplayString);
  237.  
  238.   list[n++] = GLX_BUFFER_SIZE;
  239.   list[n++] = 1;
  240.   if (GLUT_WIND_IS_DOUBLE(mode)) {
  241.     list[n++] = GLX_DOUBLEBUFFER;
  242.   }
  243.   if (GLUT_WIND_IS_STEREO(mode)) {
  244.     list[n++] = GLX_STEREO;
  245.   }
  246.   if (GLUT_WIND_HAS_DEPTH(mode)) {
  247.     list[n++] = GLX_DEPTH_SIZE;
  248.     list[n++] = 1;
  249.   }
  250.   if (GLUT_WIND_HAS_STENCIL(mode)) {
  251.     list[n++] = GLX_STENCIL_SIZE;
  252.     list[n++] = 1;
  253.   }
  254.   list[n] = (int) None; /* terminate list */
  255.  
  256.   /* glXChooseVisual specify GLX_BUFFER_SIZE prefers the
  257.      "smallest index buffer of at least the specified size".
  258.      This would be reasonable if GLUT allowed the user to
  259.      specify the required buffe size, but GLUT's display mode
  260.      is too simplistic (easy to use?). GLUT should try to find
  261.      the "largest".  So start with a large buffer size and
  262.      shrink until we find a matching one that exists. */
  263.  
  264.   for (i = 0; bufSizeList[i]; i++) {
  265.     /* XXX Assumes list[1] is where GLX_BUFFER_SIZE parameter
  266.        is. */
  267.     list[1] = bufSizeList[i];
  268.     vi = glXChooseVisual(__glutDisplay,
  269.       __glutScreen, list);
  270.     if (vi)
  271.       return vi;
  272.   }
  273.   return NULL;
  274. }
  275.  
  276. static XVisualInfo *
  277. getVisualInfoRGB(unsigned int mode)
  278. {
  279.   int list[32];
  280.   int n = 0;
  281.  
  282.   /* Should not be looking at display mode mask if
  283.      __glutDisplayString is non-NULL. */
  284.   assert(!__glutDisplayString);
  285.  
  286.   /* XXX Would a caching mechanism to minize the calls to
  287.      glXChooseVisual? You'd have to reference count
  288.      XVisualInfo* pointers.  Would also have to properly
  289.      interact with glutInitDisplayString. */
  290.  
  291.   list[n++] = GLX_RGBA;
  292.   list[n++] = GLX_RED_SIZE;
  293.   list[n++] = 1;
  294.   list[n++] = GLX_GREEN_SIZE;
  295.   list[n++] = 1;
  296.   list[n++] = GLX_BLUE_SIZE;
  297.   list[n++] = 1;
  298.   if (GLUT_WIND_HAS_ALPHA(mode)) {
  299.     list[n++] = GLX_ALPHA_SIZE;
  300.     list[n++] = 1;
  301.   }
  302.   if (GLUT_WIND_IS_DOUBLE(mode)) {
  303.     list[n++] = GLX_DOUBLEBUFFER;
  304.   }
  305.   if (GLUT_WIND_IS_STEREO(mode)) {
  306.     list[n++] = GLX_STEREO;
  307.   }
  308.   if (GLUT_WIND_HAS_DEPTH(mode)) {
  309.     list[n++] = GLX_DEPTH_SIZE;
  310.     list[n++] = 1;
  311.   }
  312.   if (GLUT_WIND_HAS_STENCIL(mode)) {
  313.     list[n++] = GLX_STENCIL_SIZE;
  314.     list[n++] = 1;
  315.   }
  316.   if (GLUT_WIND_HAS_ACCUM(mode)) {
  317.     list[n++] = GLX_ACCUM_RED_SIZE;
  318.     list[n++] = 1;
  319.     list[n++] = GLX_ACCUM_GREEN_SIZE;
  320.     list[n++] = 1;
  321.     list[n++] = GLX_ACCUM_BLUE_SIZE;
  322.     list[n++] = 1;
  323.     if (GLUT_WIND_HAS_ALPHA(mode)) {
  324.       list[n++] = GLX_ACCUM_ALPHA_SIZE;
  325.       list[n++] = 1;
  326.     }
  327.   }
  328. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
  329.   if (GLUT_WIND_IS_MULTISAMPLE(mode)) {
  330.     if (!__glutIsSupportedByGLX("GLX_SGIS_multisample"))
  331.       return NULL;
  332.     list[n++] = GLX_SAMPLES_SGIS;
  333.     /* XXX Is 4 a reasonable minimum acceptable number of
  334.        samples? */
  335.     list[n++] = 4;
  336.   }
  337. #endif
  338.   list[n] = (int) None; /* terminate list */
  339.  
  340.   return glXChooseVisual(__glutDisplay,
  341.     __glutScreen, list);
  342. }
  343.  
  344. XVisualInfo *
  345. __glutGetVisualInfo(unsigned int mode)
  346. {
  347.   /* XXX GLUT_LUMINANCE not implemented for GLUT 3.0. */
  348.   if (GLUT_WIND_IS_LUMINANCE(mode))
  349.     return NULL;
  350.  
  351.   if (GLUT_WIND_IS_RGB(mode))
  352.     return getVisualInfoRGB(mode);
  353.   else
  354.     return getVisualInfoCI(mode);
  355. }
  356.  
  357. XVisualInfo *
  358. __glutDetermineVisual(
  359.   unsigned int displayMode,
  360.   Bool * treatAsSingle,
  361.   XVisualInfo * (getVisualInfo) (unsigned int))
  362. {
  363.   XVisualInfo *vis;
  364.  
  365.   /* Should not be looking at display mode mask if
  366.      __glutDisplayString is non-NULL. */
  367.   assert(!__glutDisplayString);
  368.  
  369.   *treatAsSingle = GLUT_WIND_IS_SINGLE(displayMode);
  370.   vis = getVisualInfo(displayMode);
  371.   if (!vis) {
  372.     /* Fallback cases when can't get exactly what was asked
  373.        for... */
  374.     if (GLUT_WIND_IS_SINGLE(displayMode)) {
  375.       /* If we can't find a single buffered visual, try looking
  376.          for a double buffered visual.  We can treat a double
  377.          buffered visual as a single buffer visual by changing
  378.          the draw buffer to GL_FRONT and treating any swap
  379.          buffers as no-ops. */
  380.       displayMode |= GLUT_DOUBLE;
  381.       vis = getVisualInfo(displayMode);
  382.       *treatAsSingle = True;
  383.     }
  384.     if (!vis && GLUT_WIND_IS_MULTISAMPLE(displayMode)) {
  385.       /* If we can't seem to get multisampling (ie, not Reality
  386.          Engine class graphics!), go without multisampling.  It
  387.          is up to the application to query how many multisamples
  388.          were allocated (0 equals no multisampling) if the
  389.          application is going to use multisampling for more than
  390.          just antialiasing. */
  391.       displayMode &= ~GLUT_MULTISAMPLE;
  392.       vis = getVisualInfo(displayMode);
  393.     }
  394.   }
  395.   return vis;
  396. }
  397.  
  398. void GLUTCALLBACK
  399. __glutDefaultDisplay(void)
  400. {
  401.   /* XXX Remove the warning after GLUT 3.0. */
  402.   __glutWarning("The following is a new check for GLUT 3.0; update your code.");
  403.   __glutFatalError(
  404.     "redisplay needed for window %d, but no display callback.",
  405.     __glutCurrentWindow->num + 1);
  406. }
  407.  
  408. void GLUTCALLBACK
  409. __glutDefaultReshape(int width, int height)
  410. {
  411.   GLUToverlay *overlay;
  412.  
  413.   /* Adjust the viewport of the window (and overlay if one
  414.      exists). */
  415.   glXMakeCurrent(__glutDisplay, __glutCurrentWindow->win,
  416.     __glutCurrentWindow->ctx);
  417.   glViewport(0, 0, (GLsizei) width, (GLsizei) height);
  418.   overlay = __glutCurrentWindow->overlay;
  419.   if (overlay) {
  420.     glXMakeCurrent(__glutDisplay, overlay->win, overlay->ctx);
  421.     glViewport(0, 0, (GLsizei) width, (GLsizei) height);
  422.   }
  423.   /* Make sure we are current to the current layer (application
  424.      should be able to count on the current layer not changing
  425.      unless the application explicitly calls glutUseLayer). */
  426.   glXMakeCurrent(__glutDisplay, __glutCurrentWindow->renderWin,
  427.     __glutCurrentWindow->renderCtx);
  428. }
  429.  
  430. XVisualInfo *
  431. __glutDetermineWindowVisual(Bool * treatAsSingle, Bool * visAlloced, void **fbc)
  432. {
  433.   if (__glutDisplayString) {
  434.  
  435.     /* __glutDisplayString should be NULL except if
  436.        glutInitDisplayString has been called to register a
  437.        different display string.  Calling glutInitDisplayString
  438.        means using a string instead of an integer mask determine
  439.        the visual to use. Using the function pointer variable
  440.        __glutDetermineVisualFromString below avoids linking in
  441.        the code for implementing glutInitDisplayString (ie,
  442.        glut_dstr.o) unless glutInitDisplayString gets called by
  443.        the application. */
  444.  
  445.     assert(__glutDetermineVisualFromString);
  446.     *visAlloced = False;
  447.     *fbc = NULL;
  448.     return __glutDetermineVisualFromString(__glutDisplayString, treatAsSingle,
  449.       requiredWindowCriteria, numRequiredWindowCriteria, requiredWindowCriteriaMask, fbc);
  450.   } else {
  451.     *visAlloced = True;
  452.     *fbc = NULL;
  453.     return __glutDetermineVisual(__glutDisplayMode,
  454.       treatAsSingle, __glutGetVisualInfo);
  455.   }
  456. }
  457.  
  458. /* ARGSUSED5 */  /* Only Win32 uses gameMode parameter. */
  459. GLUTwindow *
  460. __glutCreateWindow(GLUTwindow * parent,
  461.   int x, int y, int width, int height, int gameMode)
  462. {
  463.   GLUTwindow *window;
  464.   XSetWindowAttributes wa;
  465.   unsigned long attribMask;
  466.   int winnum;
  467.   int i;
  468. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
  469.   GLXFBConfigSGIX fbc;
  470. #else
  471.   void *fbc;
  472. #endif
  473.  
  474. #if defined(_WIN32)
  475.   WNDCLASS wc;
  476.   int style;
  477.  
  478.   if (!GetClassInfo(GetModuleHandle(NULL), "GLUT", &wc)) {
  479.     __glutOpenWin32Connection(NULL);
  480.   }
  481. #else
  482.   if (!__glutDisplay) {
  483.     __glutOpenXConnection(NULL);
  484.   }
  485. #endif
  486.   if (__glutGameModeWindow) {
  487.     __glutFatalError("cannot create windows in game mode.");
  488.   }
  489.   winnum = getUnusedWindowSlot();
  490.   window = (GLUTwindow *) malloc(sizeof(GLUTwindow));
  491.   if (!window) {
  492.     __glutFatalError("out of memory.");
  493.   }
  494.   window->num = winnum;
  495.  
  496. #if !defined(_WIN32)
  497.   window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
  498.     &window->visAlloced, (void**) &fbc);
  499.   if (!window->vis) {
  500.     __glutFatalError(
  501.       "visual with necessary capabilities not found.");
  502.   }
  503.   __glutSetupColormap(window->vis, &window->colormap, &window->cmap);
  504. #endif
  505.   window->eventMask = StructureNotifyMask | ExposureMask;
  506.  
  507.   attribMask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
  508.   wa.background_pixmap = None;
  509.   wa.border_pixel = 0;
  510.   wa.colormap = window->cmap;
  511.   wa.event_mask = window->eventMask;
  512.   if (parent) {
  513.     if (parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK)
  514.       wa.event_mask |= GLUT_HACK_STOP_PROPAGATE_MASK;
  515.     attribMask |= CWDontPropagate;
  516.     wa.do_not_propagate_mask = parent->eventMask & GLUT_DONT_PROPAGATE_FILTER_MASK;
  517.   } else {
  518.     wa.do_not_propagate_mask = 0;
  519.   }
  520.  
  521.   /* Stash width and height before Win32's __glutAdjustCoords
  522.      possibly overwrites the values. */
  523.   window->width = width;
  524.   window->height = height;
  525.   window->forceReshape = True;
  526.   window->ignoreKeyRepeat = False;
  527.  
  528. #if defined(_WIN32)
  529.   __glutAdjustCoords(parent ? parent->win : NULL,
  530.     &x, &y, &width, &height);
  531.   if (parent) {
  532.     style = WS_CHILD;
  533.   } else {
  534.     if (gameMode) {
  535.       /* Game mode window should be a WS_POPUP window to
  536.          ensure that the taskbar is hidden by it.  A standard
  537.          WS_OVERLAPPEDWINDOW does not hide the task bar. */
  538.       style = WS_POPUP | WS_MAXIMIZE;
  539.     } else {
  540.       /* A standard toplevel window with borders and such. */
  541.       style = WS_OVERLAPPEDWINDOW;
  542.     }
  543.   }
  544.   window->win = CreateWindow("GLUT", "GLUT",
  545.     WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
  546.     x, y, width, height, parent ? parent->win : __glutRoot,
  547.     NULL, GetModuleHandle(NULL), 0);
  548.   window->hdc = GetDC(window->win);
  549.   /* Must set the XHDC for fake glXChooseVisual & fake
  550.      glXCreateContext & fake XAllocColorCells. */
  551.   XHDC = window->hdc;
  552.   XHWND = window->win;
  553.   window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
  554.     &window->visAlloced, &fbc);
  555.   if (!window->vis) {
  556.     __glutFatalError(
  557.       "pixel format with necessary capabilities not found.");
  558.   }
  559.   if (!SetPixelFormat(window->hdc,
  560.       ChoosePixelFormat(window->hdc, window->vis),
  561.       window->vis)) {
  562.     __glutFatalError("SetPixelFormat failed during window create.");
  563.   }
  564.   __glutSetupColormap(window->vis, &window->colormap, &window->cmap);
  565.   /* Make sure subwindows get a windowStatus callback. */
  566.   if (parent) {
  567.     PostMessage(parent->win, WM_ACTIVATE, 0, 0);
  568.   }
  569. #else
  570.   window->win = XCreateWindow(__glutDisplay,
  571.     parent == NULL ? __glutRoot : parent->win,
  572.     x, y, width, height, 0,
  573.     window->vis->depth, InputOutput, window->vis->visual,
  574.     attribMask, &wa);
  575. #endif
  576.   window->renderWin = window->win;
  577. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
  578.   if (fbc) {
  579.     window->ctx = glXCreateContextWithConfigSGIX(__glutDisplay, fbc,
  580.       GLX_RGBA_TYPE_SGIX, None, __glutTryDirect);
  581.   } else
  582. #endif
  583.   {
  584.     window->ctx = glXCreateContext(__glutDisplay, window->vis,
  585.       None, __glutTryDirect);
  586.   }
  587.   if (!window->ctx) {
  588.     __glutFatalError(
  589.       "failed to create OpenGL rendering context.");
  590.   }
  591.   window->renderCtx = window->ctx;
  592. #if !defined(_WIN32)
  593.   window->isDirect = glXIsDirect(__glutDisplay, window->ctx);
  594.   if (__glutForceDirect) {
  595.     if (!window->isDirect)
  596.       __glutFatalError("direct rendering not possible.");
  597.   }
  598. #endif
  599.  
  600.   window->parent = parent;
  601.   if (parent) {
  602.     window->siblings = parent->children;
  603.     parent->children = window;
  604.   } else {
  605.     window->siblings = NULL;
  606.   }
  607.   window->overlay = NULL;
  608.   window->children = NULL;
  609.   window->display = __glutDefaultDisplay;
  610.   window->reshape = __glutDefaultReshape;
  611.   window->mouse = NULL;
  612.   window->motion = NULL;
  613.   window->passive = NULL;
  614.   window->entry = NULL;
  615.   window->keyboard = NULL;
  616.   window->keyboardUp = NULL;
  617.   window->windowStatus = NULL;
  618.   window->visibility = NULL;
  619.   window->special = NULL;
  620.   window->specialUp = NULL;
  621.   window->buttonBox = NULL;
  622.   window->dials = NULL;
  623.   window->spaceMotion = NULL;
  624.   window->spaceRotate = NULL;
  625.   window->spaceButton = NULL;
  626.   window->tabletMotion = NULL;
  627.   window->tabletButton = NULL;
  628. #ifdef _WIN32
  629.   window->joystick = NULL;
  630.   window->joyPollInterval = 0;
  631. #endif
  632.   window->tabletPos[0] = -1;
  633.   window->tabletPos[1] = -1;
  634.   window->shownState = 0;
  635.   window->visState = -1;  /* not VisibilityUnobscured,
  636.                              VisibilityPartiallyObscured, or
  637.                              VisibilityFullyObscured */
  638.   window->entryState = -1;  /* not EnterNotify or LeaveNotify */
  639.  
  640.   window->desiredConfMask = 0;
  641.   window->buttonUses = 0;
  642.   window->cursor = GLUT_CURSOR_INHERIT;
  643.  
  644.   /* Setup window to be mapped when glutMainLoop starts. */
  645.   window->workMask = GLUT_MAP_WORK;
  646. #ifdef _WIN32
  647.   if (gameMode) {
  648.     /* When mapping a game mode window, just show
  649.        the window.  We have already created the game
  650.        mode window with a maximize flag at creation
  651.        time.  Doing a ShowWindow(window->win, SW_SHOWNORMAL)
  652.        would be wrong for a game mode window since it
  653.        would unmaximize the window. */
  654.     window->desiredMapState = GameModeState;
  655.   } else {
  656.     window->desiredMapState = NormalState;
  657.   }
  658. #else
  659.   window->desiredMapState = NormalState;
  660. #endif
  661.   window->prevWorkWin = __glutWindowWorkList;
  662.   __glutWindowWorkList = window;
  663.  
  664.   /* Initially, no menus attached. */
  665.   for (i = 0; i < GLUT_MAX_MENUS; i++) {
  666.     window->menu[i] = 0;
  667.   }
  668.  
  669.   /* Add this new window to the window list. */
  670.   __glutWindowList[winnum] = window;
  671.  
  672.   /* Make the new window the current window. */
  673.   __glutSetWindow(window);
  674.  
  675.   __glutDetermineMesaSwapHackSupport();
  676.  
  677.   if (window->treatAsSingle) {
  678.     /* We do this because either the window really is single
  679.        buffered (in which case this is redundant, but harmless,
  680.        because this is the initial single-buffered context
  681.        state); or we are treating a double buffered window as a
  682.        single-buffered window because the system does not appear
  683.        to export any suitable single- buffered visuals (in which
  684.        the following are necessary). */
  685.     glDrawBuffer(GL_FRONT);
  686.     glReadBuffer(GL_FRONT);
  687.   }
  688.   return window;
  689. }
  690.  
  691. /* CENTRY */
  692. int APIENTRY
  693. glutCreateWindow(const char *title)
  694. {
  695.   static int firstWindow = 1;
  696.   GLUTwindow *window;
  697. #if !defined(_WIN32)
  698.   XWMHints *wmHints;
  699. #endif
  700.   Window win;
  701.   XTextProperty textprop;
  702.  
  703.   if (__glutGameModeWindow) {
  704.     __glutFatalError("cannot create windows in game mode.");
  705.   }
  706.   window = __glutCreateWindow(NULL,
  707.     __glutSizeHints.x, __glutSizeHints.y,
  708.     __glutInitWidth, __glutInitHeight,
  709.     /* not game mode */ 0);
  710.   win = window->win;
  711.   /* Setup ICCCM properties. */
  712.   textprop.value = (unsigned char *) title;
  713.   textprop.encoding = XA_STRING;
  714.   textprop.format = 8;
  715.   textprop.nitems = strlen(title);
  716. #if defined(_WIN32)
  717.   SetWindowText(win, title);
  718.   if (__glutIconic) {
  719.     window->desiredMapState = IconicState;
  720.   }
  721. #else
  722.   wmHints = XAllocWMHints();
  723.   wmHints->initial_state =
  724.     __glutIconic ? IconicState : NormalState;
  725.   wmHints->flags = StateHint;
  726.   XSetWMProperties(__glutDisplay, win, &textprop, &textprop,
  727.   /* Only put WM_COMMAND property on first window. */
  728.     firstWindow ? __glutArgv : NULL,
  729.     firstWindow ? __glutArgc : 0,
  730.     &__glutSizeHints, wmHints, NULL);
  731.   XFree(wmHints);
  732.   XSetWMProtocols(__glutDisplay, win, &__glutWMDeleteWindow, 1);
  733. #endif
  734.   firstWindow = 0;
  735.   return window->num + 1;
  736. }
  737.  
  738. int APIENTRY
  739. glutCreateSubWindow(int win, int x, int y, int width, int height)
  740. {
  741.   GLUTwindow *window;
  742.  
  743.   window = __glutCreateWindow(__glutWindowList[win - 1],
  744.     x, y, width, height, /* not game mode */ 0);
  745. #if !defined(_WIN32)
  746.   {
  747.     GLUTwindow *toplevel;
  748.  
  749.     toplevel = __glutToplevelOf(window);
  750.     if (toplevel->cmap != window->cmap) {
  751.       __glutPutOnWorkList(toplevel, GLUT_COLORMAP_WORK);
  752.     }
  753.   }
  754. #endif
  755.   return window->num + 1;
  756. }
  757. /* ENDCENTRY */
  758.  
  759. void
  760. __glutDestroyWindow(GLUTwindow * window,
  761.   GLUTwindow * initialWindow)
  762. {
  763.   GLUTwindow **prev, *cur, *parent, *siblings;
  764.  
  765.   /* Recursively destroy any children. */
  766.   cur = window->children;
  767.   while (cur) {
  768.     siblings = cur->siblings;
  769.     __glutDestroyWindow(cur, initialWindow);
  770.     cur = siblings;
  771.   }
  772.   /* Remove from parent's children list (only necessary for
  773.      non-initial windows and subwindows!). */
  774.   parent = window->parent;
  775.   if (parent && parent == initialWindow->parent) {
  776.     prev = &parent->children;
  777.     cur = parent->children;
  778.     while (cur) {
  779.       if (cur == window) {
  780.         *prev = cur->siblings;
  781.         break;
  782.       }
  783.       prev = &(cur->siblings);
  784.       cur = cur->siblings;
  785.     }
  786.   }
  787.   /* Unbind if bound to this window. */
  788.   if (window == __glutCurrentWindow) {
  789.     glXMakeCurrent(__glutDisplay, None, NULL);
  790.     __glutCurrentWindow = NULL;
  791.   }
  792.   /* Begin tearing down window itself. */
  793.   if (window->overlay) {
  794.     __glutFreeOverlayFunc(window->overlay);
  795.   }
  796.   XDestroyWindow(__glutDisplay, window->win);
  797.   glXDestroyContext(__glutDisplay, window->ctx);
  798.   if (window->colormap) {
  799.     /* Only color index windows have colormap data structure. */
  800.     __glutFreeColormap(window->colormap);
  801.   }
  802.   /* NULLing the __glutWindowList helps detect is a window
  803.      instance has been destroyed, given a window number. */
  804.   __glutWindowList[window->num] = NULL;
  805.  
  806.   /* Cleanup data structures that might contain window. */
  807.   cleanWindowWorkList(window);
  808. #if !defined(_WIN32)
  809.   cleanStaleWindowList(window);
  810. #endif
  811.   /* Remove window from the "get window cache" if it is there. */
  812.   if (__glutWindowCache == window)
  813.     __glutWindowCache = NULL;
  814.  
  815.   if (window->visAlloced) {
  816.     /* Only free XVisualInfo* gotten from glXChooseVisual. */
  817.     XFree(window->vis);
  818.   }
  819.  
  820.   if (window == __glutGameModeWindow) {
  821.     /* Destroying the game mode window should implicitly
  822.        have GLUT leave game mode. */
  823.     __glutCloseDownGameMode();
  824.   }
  825.  
  826.   free(window);
  827. }
  828.  
  829. /* CENTRY */
  830. void APIENTRY
  831. glutDestroyWindow(int win)
  832. {
  833.   GLUTwindow *window = __glutWindowList[win - 1];
  834.  
  835.   if (__glutMappedMenu && __glutMenuWindow == window) {
  836.     __glutFatalUsage("destroying menu window not allowed while menus in use");
  837.   }
  838. #if !defined(_WIN32)
  839.   /* If not a toplevel window... */
  840.   if (window->parent) {
  841.     /* Destroying subwindows may change colormap requirements;
  842.        recalculate toplevel window's WM_COLORMAP_WINDOWS
  843.        property. */
  844.     __glutPutOnWorkList(__glutToplevelOf(window->parent),
  845.       GLUT_COLORMAP_WORK);
  846.   }
  847. #endif
  848.   __glutDestroyWindow(window, window);
  849. }
  850. /* ENDCENTRY */
  851.  
  852. void
  853. __glutChangeWindowEventMask(long eventMask, Bool add)
  854. {
  855.   if (add) {
  856.     /* Add eventMask to window's event mask. */
  857.     if ((__glutCurrentWindow->eventMask & eventMask) !=
  858.       eventMask) {
  859.       __glutCurrentWindow->eventMask |= eventMask;
  860.       __glutPutOnWorkList(__glutCurrentWindow,
  861.         GLUT_EVENT_MASK_WORK);
  862.     }
  863.   } else {
  864.     /* Remove eventMask from window's event mask. */
  865.     if (__glutCurrentWindow->eventMask & eventMask) {
  866.       __glutCurrentWindow->eventMask &= ~eventMask;
  867.       __glutPutOnWorkList(__glutCurrentWindow,
  868.         GLUT_EVENT_MASK_WORK);
  869.     }
  870.   }
  871. }
  872.  
  873. void APIENTRY
  874. glutDisplayFunc(GLUTdisplayCB displayFunc)
  875. {
  876.   /* XXX Remove the warning after GLUT 3.0. */
  877.   if (!displayFunc)
  878.     __glutFatalError("NULL display callback not allowed in GLUT 3.0; update your code.");
  879.   __glutCurrentWindow->display = displayFunc;
  880. }
  881.  
  882. void APIENTRY
  883. glutMouseFunc(GLUTmouseCB mouseFunc)
  884. {
  885.   if (__glutCurrentWindow->mouse) {
  886.     if (!mouseFunc) {
  887.       /* Previous mouseFunc being disabled. */
  888.       __glutCurrentWindow->buttonUses--;
  889.       __glutChangeWindowEventMask(
  890.         ButtonPressMask | ButtonReleaseMask,
  891.         __glutCurrentWindow->buttonUses > 0);
  892.     }
  893.   } else {
  894.     if (mouseFunc) {
  895.       /* Previously no mouseFunc, new one being installed. */
  896.       __glutCurrentWindow->buttonUses++;
  897.       __glutChangeWindowEventMask(
  898.         ButtonPressMask | ButtonReleaseMask, True);
  899.     }
  900.   }
  901.   __glutCurrentWindow->mouse = mouseFunc;
  902. }
  903.  
  904. void APIENTRY
  905. glutMotionFunc(GLUTmotionCB motionFunc)
  906. {
  907.   /* Hack.  Some window managers (4Dwm by default) will mask
  908.      motion events if the client is not selecting for button
  909.      press and release events. So we select for press and
  910.      release events too (being careful to use reference
  911.      counting).  */
  912.   if (__glutCurrentWindow->motion) {
  913.     if (!motionFunc) {
  914.       /* previous mouseFunc being disabled */
  915.       __glutCurrentWindow->buttonUses--;
  916.       __glutChangeWindowEventMask(
  917.         ButtonPressMask | ButtonReleaseMask,
  918.         __glutCurrentWindow->buttonUses > 0);
  919.     }
  920.   } else {
  921.     if (motionFunc) {
  922.       /* Previously no mouseFunc, new one being installed. */
  923.       __glutCurrentWindow->buttonUses++;
  924.       __glutChangeWindowEventMask(
  925.         ButtonPressMask | ButtonReleaseMask, True);
  926.     }
  927.   }
  928.   /* Real work of selecting for passive mouse motion.  */
  929.   __glutChangeWindowEventMask(
  930.     Button1MotionMask | Button2MotionMask | Button3MotionMask,
  931.     motionFunc != NULL);
  932.   __glutCurrentWindow->motion = motionFunc;
  933. }
  934.  
  935. void APIENTRY
  936. glutPassiveMotionFunc(GLUTpassiveCB passiveMotionFunc)
  937. {
  938.   __glutChangeWindowEventMask(PointerMotionMask,
  939.     passiveMotionFunc != NULL);
  940.  
  941.   /* Passive motion also requires watching enters and leaves so
  942.      that a fake passive motion event can be generated on an
  943.      enter. */
  944.   __glutChangeWindowEventMask(EnterWindowMask | LeaveWindowMask,
  945.     __glutCurrentWindow->entry != NULL || passiveMotionFunc != NULL);
  946.  
  947.   __glutCurrentWindow->passive = passiveMotionFunc;
  948. }
  949.  
  950. void APIENTRY
  951. glutEntryFunc(GLUTentryCB entryFunc)
  952. {
  953.   __glutChangeWindowEventMask(EnterWindowMask | LeaveWindowMask,
  954.     entryFunc != NULL || __glutCurrentWindow->passive);
  955.   __glutCurrentWindow->entry = entryFunc;
  956.   if (!entryFunc) {
  957.     __glutCurrentWindow->entryState = -1;
  958.   }
  959. }
  960.  
  961. void APIENTRY
  962. glutWindowStatusFunc(GLUTwindowStatusCB windowStatusFunc)
  963. {
  964.   __glutChangeWindowEventMask(VisibilityChangeMask,
  965.     windowStatusFunc != NULL);
  966.   __glutCurrentWindow->windowStatus = windowStatusFunc;
  967.   if (!windowStatusFunc) {
  968.     /* Make state invalid. */
  969.     __glutCurrentWindow->visState = -1;
  970.   }
  971. }
  972.  
  973. static void GLUTCALLBACK
  974. visibilityHelper(int status)
  975. {
  976.   if (status == GLUT_HIDDEN || status == GLUT_FULLY_COVERED)
  977.     __glutCurrentWindow->visibility(GLUT_NOT_VISIBLE);
  978.   else
  979.     __glutCurrentWindow->visibility(GLUT_VISIBLE);
  980. }
  981.  
  982. void APIENTRY
  983. glutVisibilityFunc(GLUTvisibilityCB visibilityFunc)
  984. {
  985.   __glutCurrentWindow->visibility = visibilityFunc;
  986.   if (visibilityFunc)
  987.     glutWindowStatusFunc(visibilityHelper);
  988.   else
  989.     glutWindowStatusFunc(NULL);
  990. }
  991.  
  992. void APIENTRY
  993. glutReshapeFunc(GLUTreshapeCB reshapeFunc)
  994. {
  995.   if (reshapeFunc) {
  996.     __glutCurrentWindow->reshape = reshapeFunc;
  997.   } else {
  998.     __glutCurrentWindow->reshape = __glutDefaultReshape;
  999.   }
  1000. }
  1001.